import os
import sys
from pathlib import Path

from maintain_task_conf import *
from mttools import make_dir_p, cmd_remote_trust, tar_compress_file, copy_to_remote_host, pg_dump_to_file, mysql_dump_to_file, mongo_dump_to_file, logger, begin_with_list_item, \
    remove_file_or_dir, init_py_service_and_timer, get_sys_info, send_mail


class FileBackupRunner:
    def __init__(self):
        self.remote_username = None
        self.remote_port = None
        self.remote_ip = None
        self.src_path = None
        self.middle_tar_path = None
        self.remote_dst_tar_path = None

    def set_remote_host_info(self, remote_ip, remote_port, remote_username):
        """
        @param remote_ip: backup server ip
        @param remote_port: backup server ip
        @param remote_username: backup server linux user
        """
        self.remote_ip = remote_ip
        self.remote_port = remote_port
        self.remote_username = remote_username

    def set_file_backup_info(self, src_path, middle_tar_path, remote_dst_tar_path):
        """
        @param src_path: source path，can be file or dir
        @param middle_tar_path: source path will be compressed to tar.gz
        @param remote_dst_tar_path: middle file will be scp to remote path
        """
        self.src_path = src_path
        self.middle_tar_path = middle_tar_path
        make_dir_p(os.path.dirname(self.middle_tar_path))
        self.remote_dst_tar_path = remote_dst_tar_path
        cmd_remote_trust(self.remote_username, self.remote_ip,
                         "mkdir -p {}".format(os.path.dirname(self.remote_dst_tar_path)))

    def run_file_backup_task(self):
        tar_compress_file(self.src_path, self.middle_tar_path)
        remote_copy_result = copy_to_remote_host(self.middle_tar_path, self.remote_username, self.remote_ip,
                                                 self.remote_dst_tar_path,False)
        copy_msg = "\r\n\r\nsrc path:\r\n{}\r\nremote_copy_result:\r\n{}\r\n".format(self.src_path, remote_copy_result)
        return copy_msg


class PgBackupRunner(FileBackupRunner):
    def __init__(self):
        super().__init__()
        self.pg_psw = None
        self.pg_db = None
        self.pg_user = None
        self.pg_port = None
        self.pg_ip = None

    def set_pg_info(self, pg_ip, pg_port, pg_user, pg_db, pg_psw):
        self.pg_ip = pg_ip
        self.pg_port = pg_port
        self.pg_user = pg_user
        self.pg_db = pg_db
        self.pg_psw = pg_psw

    def run_pg_data_dump(self):
        pg_dump_to_file(self.pg_ip, self.pg_port, self.pg_user, self.pg_psw, self.pg_db, self.src_path)
        return self.run_file_backup_task()


class MySQLBackupRunner(FileBackupRunner):
    def __init__(self):
        super().__init__()
        self.mysql_psw = None
        self.mysql_db = None
        self.mysql_user = None
        self.mysql_port = None
        self.mysql_ip = None

    def set_mysql_info(self, mysql_ip, mysql_port, mysql_user, mysql_db, mysql_psw):
        self.mysql_ip = mysql_ip
        self.mysql_port = mysql_port
        self.mysql_user = mysql_user
        self.mysql_db = mysql_db
        self.mysql_psw = mysql_psw

    def run_mysql_data_dump(self):
        mysql_dump_to_file(ip=self.mysql_ip, port=self.mysql_port, user=self.mysql_user, dbname=self.mysql_db, psw=self.mysql_psw,
                           dst_file=self.src_path)
        return self.run_file_backup_task()


class MongoBackupRunner(FileBackupRunner):
    def __init__(self):
        super().__init__()
        self.mongo_psw = None
        self.mongo_db = None
        self.mongo_user = None
        self.mongo_port = None
        self.mongo_ip = None

    def set_mongo_info(self, mongo_ip, mongo_port, mongo_user, mongo_db, mongo_psw):
        self.mongo_ip = mongo_ip
        self.mongo_port = mongo_port
        self.mongo_user = mongo_user
        self.mongo_db = mongo_db
        self.mongo_psw = mongo_psw

    def run_mongo_data_dump(self):
        mongo_dump_to_file(self.mongo_ip, self.mongo_port, self.mongo_user, self.mongo_db, self.mongo_psw,
                           self.src_path)
        return self.run_file_backup_task()


class FileCleaner:

    def __init__(self, dir_path, pattern, file_number_to_reserve):
        """
        @param dir_path: /path
        @param pattern: *.txt,*,*.log
        @param file_number_to_reserve:123
        """
        self.dir_path = dir_path
        self.pattern = pattern
        self.file_number_to_reserve = file_number_to_reserve

    def __get_file_list_to_remove(self):
        file_list = sorted(Path(self.dir_path).glob(self.pattern),
                           key=lambda file: os.path.getctime(os.path.join(self.dir_path, file)))
        file_list = [os.path.join(self.dir_path, file) for file in file_list]
        latest_n = file_list[-self.file_number_to_reserve:]
        file_list_to_remove = list(set(file_list).difference(latest_n))
        logger.info(file_list_to_remove)
        return file_list_to_remove

    def __str__(self):
        return 'path: {} pattern： {} file number to reserve： {}'.format(self.dir_path, self.pattern,
                                                                        self.file_number_to_reserve)

    def run_clean_task(self, white_list):
        """
        @param white_list:only begin with white path, file can be remove,['/path1','/path2']
        """
        file_list_to_remove = self.__get_file_list_to_remove()
        for file in file_list_to_remove:
            if begin_with_list_item(file, white_list):
                logger.info(file)
                remove_file_or_dir(file)
        return "file list to remove:\r\n{}\r\n".format(file_list_to_remove)


def backup_task_runner():
    backup_msg = ''
    for conf in backup_file_conf_list:
        runner = FileBackupRunner()
        runner.set_remote_host_info(conf[0][0], conf[0][1], conf[0][2])
        runner.set_file_backup_info(conf[1][0], conf[1][1], conf[1][2])
        backup_msg += runner.run_file_backup_task()

    for conf in backup_pg_conf_list:
        runner = PgBackupRunner()
        runner.set_remote_host_info(conf[0][0], conf[0][1], conf[0][2])
        runner.set_file_backup_info(conf[1][0], conf[1][1], conf[1][2])
        runner.set_pg_info(conf[2][0], conf[2][1], conf[2][2], conf[2][3], conf[2][4])
        backup_msg += runner.run_pg_data_dump()

    for conf in backup_mysql_conf_list:
        runner = MySQLBackupRunner()
        runner.set_remote_host_info(conf[0][0], conf[0][1], conf[0][2])
        runner.set_file_backup_info(conf[1][0], conf[1][1], conf[1][2])
        runner.set_mysql_info(conf[2][0], conf[2][1], conf[2][2], conf[2][3], conf[2][4])
        backup_msg += runner.run_mysql_data_dump()

    for conf in backup_mongo_conf_list:
        runner = MongoBackupRunner()
        runner.set_remote_host_info(conf[0][0], conf[0][1], conf[0][2])
        runner.set_file_backup_info(conf[1][0], conf[1][1], conf[1][2])
        runner.set_mongo_info(conf[2][0], conf[2][1], conf[2][2], conf[2][3], conf[2][4])
        backup_msg += runner.run_mongo_data_dump()
    logger.debug(backup_msg)
    return backup_msg


def clean_task_runner():
    clean_msg = ''
    for cleaner_tuple in clean_config_list:
        cleaner = FileCleaner(cleaner_tuple[0], cleaner_tuple[1], cleaner_tuple[2])
        logger.info(cleaner)
        clean_msg += cleaner.run_clean_task(clean_white_list_conf)
    logger.debug(clean_msg)
    return clean_msg


if __name__ == "__main__":
    ret = init_py_service_and_timer(sys.argv, python3_bin_path,
                                    os.path.realpath(__file__),
                                    systemctl_service_name,
                                    systemctl_service_description,
                                    systemctl_service_linux_user,
                                    systemctl_timer_name,
                                    systemctl_timer_expression)
    # if init do not do task
    info = ""
    if not ret:
        info += clean_task_runner()
        info += "\r\n"
        info += backup_task_runner()

    # if send mail msg
    if mail_notification_enable:
        mail_content = "file_backup_conf_list:\r\n {}\r\n sysinfo:{}".format(
            backup_file_conf_list, get_sys_info()
        )
        mail_content += info
        send_mail(mail_host, mail_user, mail_user_psw, mail_receivers, mail_title,
                  mail_content, mail_ssl_enable)
